import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 25397
 * Date: 2021-12-05
 * Time: 10:58
 */
//ArrayList模拟实现
class MyArrayList<E>{
    private Object[] elementData;//底层数组
    private  int usedSize;//有效的数据个数
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};

    public MyArrayList(){
        this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//无参构造
    }

    public MyArrayList(int capacity) throws IllegalAccessException {//给了容量了
        if(capacity>0){//数组容量肯定要大于0
            this.elementData=new Object[capacity];
        }else if(capacity==0){
            this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }else{
            throw new IllegalAccessException("容量大小不能为负数！！！");//这里你也可以抛一个自定义异常
        }

    }

    public boolean add(E e){//添加元素，相当于存放在了顺序表最后位置
        //确定一个真正的容量
        //预测->扩容（把检查顺序表空和满以及扩容放到了一起）
        ensureCapacityInternal(usedSize+1);
        elementData[usedSize]=e;
        usedSize++;
        return true;
    }

    private void copy(int index,E e){
        for(int i=usedSize-1;i>=index;i++){
            elementData[i+1]=elementData[i];
        }
        elementData[index]=e;
    }



    public void add(int index,E e){
        //1.检查下标是否合法
        rangeCheckForAdd(index);
        //2.确定真正的容量
        ensureCapacityInternal(usedSize+1);
        //挪数据（在某个位置添加后，原先的数据要后移）
        copy(index,e);
        usedSize++;
    }
    private void rangeCheckForAdd(int index){
        if(index<0||index>size()){
            throw new IndexOutOfBoundsException("index位置不合法");
        }
    }

    //获取顺序表大小
    public int size(){
        return this.usedSize;
    }

    private void ensureCapacityInternal(int minCapacity){
        //1.计算出需要的容量
        int capacity=calculateCapacity(elementData,minCapacity);
        //2.拿着计算出的容量，去看，满了或空了就扩容
        ensureExplicitCapacity(capacity);
    }

    private void ensureExplicitCapacity(int minCapacity){//确定明确的容量
        //1.如果进不去if语句，说明数组还没有放满
        if(minCapacity-elementData.length>0){
            //扩容
            grow(minCapacity);
        }
    }

    private void grow(int minCapacity){
        int oldCapacity= elementData.length;
        int newCapacity=oldCapacity+(oldCapacity>>1);//1.5倍扩容
        if(newCapacity-minCapacity<0){
            newCapacity=minCapacity;
        }
        if(newCapacity-MAX_ARRAY_SIZE>0){
            //说明你要的容量非常大
            newCapacity=hugeCapcity(minCapacity);
        }
        elementData=Arrays.copyOf(elementData,newCapacity);
    }

    private static final int MAX_ARRAY_SIZE=Integer.MAX_VALUE-8;

    private static int hugeCapcity(int minCapacity){
        if(minCapacity<0){
            throw new OutOfMemoryError();
        }
        return (minCapacity>MAX_ARRAY_SIZE)?Integer.MAX_VALUE:MAX_ARRAY_SIZE;
    }

    private static int calculateCapacity(Object[] elementData,int minCapacity){
        //1.是否之前elementData数组分配过大小
        if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
            return Math.max(10,minCapacity);
        }
        //2.如果分配过，就返回+1后的值
        return minCapacity;
    }
}


public class TestDemo {
    public static void main(String[] args) {
        ArrayList<Student> students=new ArrayList<>();
        students.add(new Student("wxy","102",99));
        students.add(new Student("a","102",78));//重复上一行代码ctrl+d
        students.add(new Student("b","102",95));
        students.add(new Student("c","102",76));
        System.out.println(students);
    }

    /*public static void main(String[] args) {
        List<String> list=new ArrayList<>();//List是一个接口，可以用它来引用一个具体的实例对象
        ArrayList<String> list2=new ArrayList<>();//不用接口，你可以直接实例化具体的类
        list2.add("hh");
    }*/

    /*public static void main(String[] args) {
        //ArrayList创建，（推荐写法）
        //构造一个空的列表
        List<Integer> list1=new ArrayList<>();//()里面放顺序表的长度

        //构造一个具有10容量的列表
        List<Integer> list2=new ArrayList<>(10);
        list2.add(1);
        list2.add(2);
        list2.add(3);
        //list2.add("hhh");//会报错，List<Integer已经限定了list2中只能放整形
        System.out.println(list2);//打印[1,2,3]

        //使用另一个ArrayList对list3进行初始化
        ArrayList<Integer> list3=new ArrayList<>(list2);//可以把list2的对象作为参数传给构造方法
        //需要注意的是，如果是Integer类型的ArrayList（也就是ArrayList<Integer>）
        // 如果你传参为list，那你的参数的list也必须是Integer的
        System.out.println(list3);//打印[1,2,3]
    }*/


    /*public static void main(String[] args) {
        List<Integer> list=new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        //使用for循环+下标遍历
        //list底层是一个数组，下标从0开始
        for(int i=0;i<list.size();i++){
            System.out.print(list.get(i)+" ");
            //get（i）会返回数组下标为i的元素
            //返回值为E类型，也就是我们指定的类型，这里是Integer
        }//打印1 2 3 4
        System.out.println();

        //使用foreach遍历
        //ArrayList实现了Iterable接口，所以它可以用foreach进行打印
        //ps:用法——for(元素的类型 数组元素 ：数组)
        //list底层就是一个数组
        for(Integer integer:list){
            System.out.print(integer+" ");
        }//打印1 2 3 4
        System.out.println();

        //使用迭代器进行打印
        //使用迭代器需要调用方法iterator
        Iterator<Integer> iterator=list.iterator();
        //iterator方法返回值类型为Iterator,我们用Iterator类型的接收
        //接收的都是Integer的（因为这里是Iterator<Integer> ）
        while(iterator.hasNext()){
            //hasNext()方法，判断数组下面一个位置还有没有数，
            // 有就返回true，并且向数组后一位移动
            System.out.print(iterator.next()+" ");
        }//打印1 2 3 4
        System.out.println();

        //还有一种专门打印list相关的迭代器listIterator（它继承了Iterator）
        ListIterator<Integer> iterator1=list.listIterator();
        while(iterator1.hasNext()){
            System.out.print(iterator1.next()+" ");
        }//打印1 2 3 4
        //ListIterator还有add，remove（对list进行添加和删除）等非常常用的功能
        System.out.println();

        //ps：使用remove和add的注意事项
        ArrayList<String> list2=new ArrayList<>();
        list2.add("hhh");
        list2.add("niHao");
        list2.add("yyy");
        ListIterator<String> iterator2= list2.listIterator();
       *//* while(iterator2.hasNext()){
            String ret=iterator2.next();
            if(ret.equals("niHao")){
                iterator2.remove();//需要先使用next方法迭代出集合中的元素，然后才能调用remove方法
            }else{
                System.out.print(ret+" ");
            }
        }
        System.out.println();*//*

        while(iterator2.hasNext()){
            String ret=iterator2.next();
            if(ret.equals("hhh")){
                iterator2.add("xxx");//需要先使用next方法迭代出集合中的元素，然后才能调用add方法
            }else{
                System.out.print(ret+" ");
            }
        }//这里打印niHao yyy
        //因为你第一次进来等于hhh，所以是没有打印的，然后你添加了一个xxx（放在hhh之后，niHao之前）,添加了xxx后，迭代的下一位置默认还是niHao，所以这里xxx不打印
        System.out.println(list2);
    }*/


    /*public static void main(String[] args) {
        //基本方法介绍


        //1. add
        ArrayList<String> list=new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");//list底层是一个数组，add方法默认插入到数组最后一个位置（尾插）
        System.out.println(list);//打印[a,b,c]

        //当然了，你也可以通过传参给add方法 来实现需要位置的插入
        list.add(1,"hhh");//往下标1的地方插入字符串hhh
        System.out.println(list);//打印[a, hhh, b, c]

        //2. addAll
        //已有一个list，你可以再来一个list2整体放进list里
        ArrayList<String> list2=new ArrayList<>();
        list2.add("一个测试");
        list.addAll(list2);
        System.out.println(list);//打印[a, hhh, b, c, 一个测试]，这里也是默认尾插


        //3. remove
        String ret=list.remove(1);//删除下标为1的元素,remove会返回删除的元素
        System.out.println(ret);//打印hhh
        System.out.println(list);//打印[a, b, c, 一个测试]
        //也可以删除一个具体的数据
        list.remove("a");
        System.out.println(list);//打印[b, c, 一个测试]

        //4. set
        list.set(0,"d");//把下标0的位置数据更改为d
        System.out.println(list);//打印[d, c, 一个测试]

        //5.contains
        //判断list中是否包含某个元素
        System.out.println(list.contains("c"));//打印true
        System.out.println(list.contains("a"));//打印false

        //6. indexOf
        //查找某个元素下标
        System.out.println(list.indexOf("c"));//打印1

        //7. lastIndexOf
        //查找最后一次出现数据x 的下标
        //比如我们现在list3里面有a c c c b
        ArrayList<String> list3=new ArrayList<>();
        list3.add("a");
        list3.add("c");
        list3.add("g");
        list3.add("c");
        list3.add("b");
        System.out.println(list3.lastIndexOf("c"));//打印3

        //8. subList
        //截取list中的一部分，返回一个List<E>类型的数据，如果你list是String的，那E就是String
        List<String> tmp=list3.subList(1,3);//从1下标开始截取，截取到下标3的位置，左闭右开（1下标截取，2下标截取，3下标不截取）
        System.out.println(tmp);



        //9. clear
        list.clear();//清空list里的数据
        System.out.println(list);

    }*/



    /*public static void main(String[] args) {
        ArrayList<String> list1=new ArrayList<>();//初始大小为？
        ArrayList<String> list2=new ArrayList<>(20);//初始大小为20
        list1.add("hhh");
        System.out.println(list1);
    }*/


    /*public static void main(String[] args) {
        MyArrayList<String> list=new MyArrayList<>();
        list.add("jhh");
        System.out.println(list);
    }*/

}
